package classify;

import weka.core.Instances;
import weka.core.converters.ConverterUtils.DataSource;
import java.util.*;

public class KNN {
    private static class Data implements Comparable<Data> {
        public double[] data;
        public double distince;
        public String label;

        Data(double[] data, String label) {
            this.data = data;
            this.label = label;
        }

        public int compareTo(Data arg) {
            return Double.compare(this.distince,arg.distince);
        }
    }

    private static void calDistince(List<Data> knnModelList, Data prediction) {
        double distince;
        for (Data m : knnModelList) {
            distince=0;
            for(int i=0;i<m.data.length;i++){
                distince+=(m.data[i]-prediction.data[i])*(m.data[i]-prediction.data[i]);
            }
            distince = Math.sqrt(distince);
            m.distince = distince;
        }
    }

    private static String findMostData(List<Data> knnModelList) {
        Map<String, Integer> typeCountMap = new HashMap<String, Integer>();
        String label = "";
        Integer tempVal = 0;
        // 统计分类个数
        for (Data model : knnModelList) {
            if (typeCountMap.containsKey(model.label)) {
                typeCountMap.put(model.label, typeCountMap.get(model.label) + 1);
            } else {
                typeCountMap.put(model.label, 1);
            }
        }
        // 找出最多分类
        for (Map.Entry<String, Integer> entry : typeCountMap.entrySet()) {
            if (entry.getValue() > tempVal) {
                tempVal = entry.getValue();
                label = entry.getKey();
            }
        }
        return label;
    }

    public static String calKNN(int k, List<Data> knnModelList, Data inputModel) {
        calDistince(knnModelList, inputModel);
        Collections.sort(knnModelList);
        List<Data> knn_newModel=new ArrayList<Data>();
        for(int i=0;i<k;i++){
            knn_newModel.add(knnModelList.get(i));
        }
        String label = findMostData(knn_newModel);
        return label;
    }

    public static void main(String[] args) throws Exception {
        DataSource train_source = new DataSource("/home/tang/实验三/数据/forKNN/iris.2D.train.arff");
        DataSource test_source = new DataSource("/home/tang/实验三/数据/forKNN/iris.2D.test.arff");
        Instances instances= train_source.getDataSet();
        Instances test_instances= test_source.getDataSet();
        List<Data> knnModelList = new ArrayList<Data>();
        int i,j,attribute,right_num=0;
        for(i=0,attribute=instances.numAttributes();i<instances.size();i++){
            double []data=new double[attribute-1];
            for(j=0;j<attribute-1;j++){
                data[j]=instances.get(i).value(j);
            }
            knnModelList.add(new Data(data,instances.get(i).stringValue(attribute-1)));
        }

        List<Data> knn_test = new ArrayList<Data>();
        for(i=0,attribute=test_instances.numAttributes();i<test_instances.size();i++){
            double []data=new double[attribute-1];
            for(j=0;j<attribute-1;j++){
                data[j]=instances.get(i).value(j);
            }
            String label=instances.get(i).stringValue(attribute-1);
            knn_test.add(new Data(data,label));
            String result = calKNN(3, knnModelList, knn_test.get(i));
            if(result==label){
                right_num++;
            }
            System.out.println(instances.instance(i).toString()+"  预测结果： "+result);
        }
        System.out.println("正确率为："+1.0*right_num/test_instances.size());
    }
}
